package org.example.sdk;

import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.stream.Stream;

@Repository
public class ResourceRepositoryImpl<T> implements ResourceRepository<T> {

    @Override
    public FindResult<T> find(Query query) {
        Store<T> store = getStore();
        Index<T> index = getIndex(store, query);

        List<T> list = findList(index, query);
        Long total = count(index, query);
        Object nextToken = null;
        if (!list.isEmpty()) {
            T last = list.get(list.size() - 1);
            nextToken = getNextToken(index, last);
        }

        FindResult<T> findResult = new FindResult<>();
        findResult.setList(list);
        findResult.setTotal(total);
        findResult.setNextToken(nextToken);
        return findResult;
    }

    private List<T> findList(Index<T> index, Query query) {
        Stream<T> stream = index.values().stream();
        if (query.getNextToken() != null) {
            Object b = query.getNextToken();
            stream = stream.filter(x -> {
                Object a = index.getKeyValue(x);
                return DefaultComparator.compare(a, b) > 0;
            });
        }
        if (query.getLimit() != null) {
            stream = stream.limit(query.getLimit());
        }
        return stream.toList();
    }

    private Long count(Index<T> index, Query query) {
        return (long) index.values().size();
    }

    private Index<T> getIndex(Store<T> store, Query query) {
        return store.getIndex(2);
    }

    private Object getNextToken(Index<T> index, T last) {
        return index.getKeyValue(last);
    }

    @SuppressWarnings("unchecked")
    private Store<T> getStore() {
        return (Store<T>) store;
    }

    private static final UserStore store = new UserStore(() -> {
        User[] users = new User[1007];
        for (int i = 0; i < users.length; i++) {
            int id = i + 1;
            String name = "user" + id;
            int uid = i / 3 + 1;
            int ord = i % 3 + 1;
            users[i] = new User(id, name, uid, ord);
        }
        return users;
    });


}
